{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "id": "igMyGnjE9hEp"
   },
   "outputs": [],
   "source": [
    "import csv\n",
    "\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import tensorflow as tf\n",
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "RANDOM_SEED = 42"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "t2HDvhIu9hEr"
   },
   "source": [
    "# Specify each path"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "id": "9NvZP2Zn9hEy"
   },
   "outputs": [],
   "source": [
    "# Specify data paths\n",
    "dataset = 'model/keypoint_classifier/keypoint.csv'\n",
    "model_save_path = 'model/keypoint_classifier/keypoint_classifier.hdf5'\n",
    "tflite_save_path = 'model/keypoint_classifier/keypoint_classifier.tflite'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "s5oMH7x19hEz"
   },
   "source": [
    "# Set number of classes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "id": "du4kodXL9hEz"
   },
   "outputs": [],
   "source": [
    "# Change training classes if necessary\n",
    "NUM_CLASSES = 10"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "XjnL0uso9hEz"
   },
   "source": [
    "# Dataset reading"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "id": "QT5ZqtEz9hE0"
   },
   "outputs": [],
   "source": [
    "X_dataset = np.loadtxt(dataset, delimiter=',', dtype='float32', usecols=list(range(1, (21 * 2) + 1)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "id": "QmoKFsp49hE0"
   },
   "outputs": [],
   "source": [
    "y_dataset = np.loadtxt(dataset, delimiter=',', dtype='int32', usecols=(0))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "id": "xQU7JTZ_9hE0"
   },
   "outputs": [],
   "source": [
    "X_train, X_test, y_train, y_test = train_test_split(X_dataset, y_dataset, train_size=0.75, random_state=RANDOM_SEED)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 279
    },
    "id": "xElG5FoPDQO9",
    "outputId": "2ef372ed-62e3-49c1-ad36-a5b5dc76701a"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), array([1595, 1663, 1510,  672,  164,  207,  139,  190,  206,  206],\n",
      "      dtype=int64))\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Classes count\n",
    "counts = np.unique(y_dataset, return_counts=True)\n",
    "df = pd.DataFrame(counts)\n",
    "df.T.plot(kind=\"bar\", stacked=True)\n",
    "print(counts)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "mxK_lETT9hE0"
   },
   "source": [
    "# Model building"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "id": "vHBmUf1t9hE1"
   },
   "outputs": [],
   "source": [
    "model = tf.keras.models.Sequential([\n",
    "    tf.keras.layers.InputLayer((21 * 2, )),\n",
    "    tf.keras.layers.Dropout(0.0),\n",
    "    tf.keras.layers.Dense(32, activation='relu'),\n",
    "    tf.keras.layers.Dropout(0.0),\n",
    "    tf.keras.layers.Dense(32, activation='relu'),\n",
    "    tf.keras.layers.Dropout(0.0),\n",
    "    tf.keras.layers.Dense(16, activation='relu'),\n",
    "    tf.keras.layers.Dense(NUM_CLASSES, activation='softmax')\n",
    "])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "ypqky9tc9hE1",
    "outputId": "c42f3550-ceee-45b8-d40d-d99fd84a2616"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"sequential\"\n",
      "_________________________________________________________________\n",
      " Layer (type)                Output Shape              Param #   \n",
      "=================================================================\n",
      " dropout (Dropout)           (None, 42)                0         \n",
      "                                                                 \n",
      " dense (Dense)               (None, 32)                1376      \n",
      "                                                                 \n",
      " dropout_1 (Dropout)         (None, 32)                0         \n",
      "                                                                 \n",
      " dense_1 (Dense)             (None, 32)                1056      \n",
      "                                                                 \n",
      " dropout_2 (Dropout)         (None, 32)                0         \n",
      "                                                                 \n",
      " dense_2 (Dense)             (None, 16)                528       \n",
      "                                                                 \n",
      " dense_3 (Dense)             (None, 10)                170       \n",
      "                                                                 \n",
      "=================================================================\n",
      "Total params: 3,130\n",
      "Trainable params: 3,130\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "model.summary()  # tf.keras.utils.plot_model(model, show_shapes=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "id": "MbMjOflQ9hE1"
   },
   "outputs": [],
   "source": [
    "# Model checkpoint callback\n",
    "cp_callback = tf.keras.callbacks.ModelCheckpoint(\n",
    "    model_save_path, verbose=1, save_weights_only=False, save_best_only=True)\n",
    "# Callback for early stopping\n",
    "es_callback = tf.keras.callbacks.EarlyStopping(patience=50, verbose=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "id": "c3Dac0M_9hE2"
   },
   "outputs": [],
   "source": [
    "# Model compilation\n",
    "model.compile(\n",
    "    optimizer='adam',\n",
    "    loss='sparse_categorical_crossentropy',\n",
    "    metrics=['accuracy']\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "7XI0j1Iu9hE2"
   },
   "source": [
    "# Model training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "id": "WirBl-JE9hE3",
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/1000\n",
      "50/77 [==================>...........] - ETA: 0s - loss: 2.1037 - accuracy: 0.2316 \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 1: val_loss improved from inf to 1.55905, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 1s 3ms/step - loss: 1.9752 - accuracy: 0.3059 - val_loss: 1.5591 - val_accuracy: 0.5775\n",
      "Epoch 2/1000\n",
      "51/77 [==================>...........] - ETA: 0s - loss: 1.3511 - accuracy: 0.6088\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 2: val_loss improved from 1.55905 to 0.97670, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 1.2533 - accuracy: 0.6394 - val_loss: 0.9767 - val_accuracy: 0.7283\n",
      "Epoch 3/1000\n",
      "57/77 [=====================>........] - ETA: 0s - loss: 0.8638 - accuracy: 0.7368\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 3: val_loss improved from 0.97670 to 0.69553, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.8367 - accuracy: 0.7407 - val_loss: 0.6955 - val_accuracy: 0.7827\n",
      "Epoch 4/1000\n",
      "47/77 [=================>............] - ETA: 0s - loss: 0.6591 - accuracy: 0.7726\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 4: val_loss improved from 0.69553 to 0.53079, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.6256 - accuracy: 0.7806 - val_loss: 0.5308 - val_accuracy: 0.8126\n",
      "Epoch 5/1000\n",
      "53/77 [===================>..........] - ETA: 0s - loss: 0.5032 - accuracy: 0.8107\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 5: val_loss improved from 0.53079 to 0.40865, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.4808 - accuracy: 0.8223 - val_loss: 0.4087 - val_accuracy: 0.8687\n",
      "Epoch 6/1000\n",
      "51/77 [==================>...........] - ETA: 0s - loss: 0.3875 - accuracy: 0.8833\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 6: val_loss improved from 0.40865 to 0.32486, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.3779 - accuracy: 0.8928 - val_loss: 0.3249 - val_accuracy: 0.9072\n",
      "Epoch 7/1000\n",
      "50/77 [==================>...........] - ETA: 0s - loss: 0.3066 - accuracy: 0.9222\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 7: val_loss improved from 0.32486 to 0.26098, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.2961 - accuracy: 0.9300 - val_loss: 0.2610 - val_accuracy: 0.9408\n",
      "Epoch 8/1000\n",
      "54/77 [====================>.........] - ETA: 0s - loss: 0.2459 - accuracy: 0.9447\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 8: val_loss improved from 0.26098 to 0.21809, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.2417 - accuracy: 0.9455 - val_loss: 0.2181 - val_accuracy: 0.9505\n",
      "Epoch 9/1000\n",
      "46/77 [================>.............] - ETA: 0s - loss: 0.2066 - accuracy: 0.9558\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 9: val_loss improved from 0.21809 to 0.18573, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.2021 - accuracy: 0.9560 - val_loss: 0.1857 - val_accuracy: 0.9603\n",
      "Epoch 10/1000\n",
      "51/77 [==================>...........] - ETA: 0s - loss: 0.1849 - accuracy: 0.9614\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 10: val_loss improved from 0.18573 to 0.16863, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.1739 - accuracy: 0.9628 - val_loss: 0.1686 - val_accuracy: 0.9560\n",
      "Epoch 11/1000\n",
      "50/77 [==================>...........] - ETA: 0s - loss: 0.1498 - accuracy: 0.9681\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 11: val_loss improved from 0.16863 to 0.15126, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.1493 - accuracy: 0.9681 - val_loss: 0.1513 - val_accuracy: 0.9609\n",
      "Epoch 12/1000\n",
      "46/77 [================>.............] - ETA: 0s - loss: 0.1334 - accuracy: 0.9715\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 12: val_loss improved from 0.15126 to 0.14801, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.1370 - accuracy: 0.9715 - val_loss: 0.1480 - val_accuracy: 0.9658\n",
      "Epoch 13/1000\n",
      "47/77 [=================>............] - ETA: 0s - loss: 0.1221 - accuracy: 0.9754\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 13: val_loss improved from 0.14801 to 0.12837, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.1203 - accuracy: 0.9752 - val_loss: 0.1284 - val_accuracy: 0.9731\n",
      "Epoch 14/1000\n",
      "51/77 [==================>...........] - ETA: 0s - loss: 0.1220 - accuracy: 0.9709\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 14: val_loss improved from 0.12837 to 0.11683, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.1180 - accuracy: 0.9723 - val_loss: 0.1168 - val_accuracy: 0.9719\n",
      "Epoch 15/1000\n",
      "52/77 [===================>..........] - ETA: 0s - loss: 0.1023 - accuracy: 0.9784\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 15: val_loss improved from 0.11683 to 0.10918, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.1007 - accuracy: 0.9784 - val_loss: 0.1092 - val_accuracy: 0.9701\n",
      "Epoch 16/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0947 - accuracy: 0.9777\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 16: val_loss improved from 0.10918 to 0.10567, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0943 - accuracy: 0.9776 - val_loss: 0.1057 - val_accuracy: 0.9750\n",
      "Epoch 17/1000\n",
      "54/77 [====================>.........] - ETA: 0s - loss: 0.0891 - accuracy: 0.9803\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 17: val_loss improved from 0.10567 to 0.09718, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0881 - accuracy: 0.9815 - val_loss: 0.0972 - val_accuracy: 0.9762\n",
      "Epoch 18/1000\n",
      "50/77 [==================>...........] - ETA: 0s - loss: 0.0818 - accuracy: 0.9825\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 18: val_loss improved from 0.09718 to 0.09687, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0835 - accuracy: 0.9809 - val_loss: 0.0969 - val_accuracy: 0.9768\n",
      "Epoch 19/1000\n",
      "46/77 [================>.............] - ETA: 0s - loss: 0.0871 - accuracy: 0.9783\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 19: val_loss improved from 0.09687 to 0.09410, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0790 - accuracy: 0.9817 - val_loss: 0.0941 - val_accuracy: 0.9762\n",
      "Epoch 20/1000\n",
      "51/77 [==================>...........] - ETA: 0s - loss: 0.0708 - accuracy: 0.9862\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 20: val_loss improved from 0.09410 to 0.08670, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0735 - accuracy: 0.9833 - val_loss: 0.0867 - val_accuracy: 0.9792\n",
      "Epoch 21/1000\n",
      "52/77 [===================>..........] - ETA: 0s - loss: 0.0712 - accuracy: 0.9850\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 21: val_loss improved from 0.08670 to 0.08653, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0696 - accuracy: 0.9851 - val_loss: 0.0865 - val_accuracy: 0.9786\n",
      "Epoch 22/1000\n",
      "54/77 [====================>.........] - ETA: 0s - loss: 0.0669 - accuracy: 0.9821\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 22: val_loss improved from 0.08653 to 0.08012, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0684 - accuracy: 0.9815 - val_loss: 0.0801 - val_accuracy: 0.9786\n",
      "Epoch 23/1000\n",
      "47/77 [=================>............] - ETA: 0s - loss: 0.0612 - accuracy: 0.9844\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 23: val_loss improved from 0.08012 to 0.07710, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0647 - accuracy: 0.9839 - val_loss: 0.0771 - val_accuracy: 0.9792\n",
      "Epoch 24/1000\n",
      "51/77 [==================>...........] - ETA: 0s - loss: 0.0592 - accuracy: 0.9856\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 24: val_loss improved from 0.07710 to 0.07600, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0615 - accuracy: 0.9833 - val_loss: 0.0760 - val_accuracy: 0.9817\n",
      "Epoch 25/1000\n",
      "57/77 [=====================>........] - ETA: 0s - loss: 0.0583 - accuracy: 0.9844\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 25: val_loss improved from 0.07600 to 0.07469, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0578 - accuracy: 0.9841 - val_loss: 0.0747 - val_accuracy: 0.9799\n",
      "Epoch 26/1000\n",
      "53/77 [===================>..........] - ETA: 0s - loss: 0.0538 - accuracy: 0.9864\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 26: val_loss improved from 0.07469 to 0.07000, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0548 - accuracy: 0.9862 - val_loss: 0.0700 - val_accuracy: 0.9823\n",
      "Epoch 27/1000\n",
      "55/77 [====================>.........] - ETA: 0s - loss: 0.0533 - accuracy: 0.9855\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 27: val_loss did not improve from 0.07000\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0519 - accuracy: 0.9864 - val_loss: 0.0752 - val_accuracy: 0.9805\n",
      "Epoch 28/1000\n",
      "53/77 [===================>..........] - ETA: 0s - loss: 0.0582 - accuracy: 0.9829\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 28: val_loss improved from 0.07000 to 0.06672, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0540 - accuracy: 0.9847 - val_loss: 0.0667 - val_accuracy: 0.9823\n",
      "Epoch 29/1000\n",
      "55/77 [====================>.........] - ETA: 0s - loss: 0.0536 - accuracy: 0.9847\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 29: val_loss did not improve from 0.06672\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0502 - accuracy: 0.9864 - val_loss: 0.0669 - val_accuracy: 0.9841\n",
      "Epoch 30/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0430 - accuracy: 0.9872\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 30: val_loss improved from 0.06672 to 0.06216, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0443 - accuracy: 0.9864 - val_loss: 0.0622 - val_accuracy: 0.9829\n",
      "Epoch 31/1000\n",
      "55/77 [====================>.........] - ETA: 0s - loss: 0.0427 - accuracy: 0.9881\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 31: val_loss did not improve from 0.06216\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0419 - accuracy: 0.9886 - val_loss: 0.0628 - val_accuracy: 0.9847\n",
      "Epoch 32/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0450 - accuracy: 0.9855\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 32: val_loss did not improve from 0.06216\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0427 - accuracy: 0.9872 - val_loss: 0.0681 - val_accuracy: 0.9811\n",
      "Epoch 33/1000\n",
      "47/77 [=================>............] - ETA: 0s - loss: 0.0382 - accuracy: 0.9904\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 33: val_loss did not improve from 0.06216\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0399 - accuracy: 0.9888 - val_loss: 0.0628 - val_accuracy: 0.9835\n",
      "Epoch 34/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0363 - accuracy: 0.9894\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 34: val_loss did not improve from 0.06216\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0383 - accuracy: 0.9892 - val_loss: 0.0656 - val_accuracy: 0.9805\n",
      "Epoch 35/1000\n",
      "49/77 [==================>...........] - ETA: 0s - loss: 0.0368 - accuracy: 0.9869\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 35: val_loss did not improve from 0.06216\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0366 - accuracy: 0.9886 - val_loss: 0.0622 - val_accuracy: 0.9823\n",
      "Epoch 36/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0348 - accuracy: 0.9894\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 36: val_loss improved from 0.06216 to 0.05727, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0347 - accuracy: 0.9888 - val_loss: 0.0573 - val_accuracy: 0.9860\n",
      "Epoch 37/1000\n",
      "53/77 [===================>..........] - ETA: 0s - loss: 0.0358 - accuracy: 0.9906\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 37: val_loss improved from 0.05727 to 0.05403, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0346 - accuracy: 0.9896 - val_loss: 0.0540 - val_accuracy: 0.9841\n",
      "Epoch 38/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0321 - accuracy: 0.9902\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 38: val_loss did not improve from 0.05403\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0333 - accuracy: 0.9900 - val_loss: 0.0540 - val_accuracy: 0.9853\n",
      "Epoch 39/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0315 - accuracy: 0.9922\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 39: val_loss did not improve from 0.05403\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0306 - accuracy: 0.9923 - val_loss: 0.0583 - val_accuracy: 0.9823\n",
      "Epoch 40/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0325 - accuracy: 0.9900\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 40: val_loss improved from 0.05403 to 0.05283, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0311 - accuracy: 0.9915 - val_loss: 0.0528 - val_accuracy: 0.9866\n",
      "Epoch 41/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0291 - accuracy: 0.9927\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 41: val_loss did not improve from 0.05283\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0303 - accuracy: 0.9919 - val_loss: 0.0585 - val_accuracy: 0.9841\n",
      "Epoch 42/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0302 - accuracy: 0.9927\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 42: val_loss improved from 0.05283 to 0.05003, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0296 - accuracy: 0.9917 - val_loss: 0.0500 - val_accuracy: 0.9866\n",
      "Epoch 43/1000\n",
      "55/77 [====================>.........] - ETA: 0s - loss: 0.0277 - accuracy: 0.9920\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 43: val_loss improved from 0.05003 to 0.04996, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0271 - accuracy: 0.9917 - val_loss: 0.0500 - val_accuracy: 0.9878\n",
      "Epoch 44/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0311 - accuracy: 0.9914\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 44: val_loss did not improve from 0.04996\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0283 - accuracy: 0.9923 - val_loss: 0.0516 - val_accuracy: 0.9872\n",
      "Epoch 45/1000\n",
      "55/77 [====================>.........] - ETA: 0s - loss: 0.0267 - accuracy: 0.9909\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 45: val_loss did not improve from 0.04996\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0262 - accuracy: 0.9915 - val_loss: 0.0564 - val_accuracy: 0.9860\n",
      "Epoch 46/1000\n",
      "54/77 [====================>.........] - ETA: 0s - loss: 0.0218 - accuracy: 0.9933\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 46: val_loss improved from 0.04996 to 0.04951, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0244 - accuracy: 0.9925 - val_loss: 0.0495 - val_accuracy: 0.9908\n",
      "Epoch 47/1000\n",
      "53/77 [===================>..........] - ETA: 0s - loss: 0.0248 - accuracy: 0.9929\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 47: val_loss did not improve from 0.04951\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0263 - accuracy: 0.9925 - val_loss: 0.0572 - val_accuracy: 0.9847\n",
      "Epoch 48/1000\n",
      "54/77 [====================>.........] - ETA: 0s - loss: 0.0260 - accuracy: 0.9928\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 48: val_loss improved from 0.04951 to 0.04799, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0256 - accuracy: 0.9923 - val_loss: 0.0480 - val_accuracy: 0.9878\n",
      "Epoch 49/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0255 - accuracy: 0.9927\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 49: val_loss did not improve from 0.04799\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0241 - accuracy: 0.9927 - val_loss: 0.0510 - val_accuracy: 0.9866\n",
      "Epoch 50/1000\n",
      "52/77 [===================>..........] - ETA: 0s - loss: 0.0230 - accuracy: 0.9922\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 50: val_loss did not improve from 0.04799\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0225 - accuracy: 0.9923 - val_loss: 0.0490 - val_accuracy: 0.9908\n",
      "Epoch 51/1000\n",
      "51/77 [==================>...........] - ETA: 0s - loss: 0.0232 - accuracy: 0.9936\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 51: val_loss improved from 0.04799 to 0.04483, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0231 - accuracy: 0.9937 - val_loss: 0.0448 - val_accuracy: 0.9921\n",
      "Epoch 52/1000\n",
      "50/77 [==================>...........] - ETA: 0s - loss: 0.0214 - accuracy: 0.9941\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 52: val_loss improved from 0.04483 to 0.04216, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0214 - accuracy: 0.9933 - val_loss: 0.0422 - val_accuracy: 0.9902\n",
      "Epoch 53/1000\n",
      "49/77 [==================>...........] - ETA: 0s - loss: 0.0257 - accuracy: 0.9914\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 53: val_loss did not improve from 0.04216\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0233 - accuracy: 0.9927 - val_loss: 0.0460 - val_accuracy: 0.9878\n",
      "Epoch 54/1000\n",
      "55/77 [====================>.........] - ETA: 0s - loss: 0.0191 - accuracy: 0.9946\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 54: val_loss did not improve from 0.04216\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0218 - accuracy: 0.9941 - val_loss: 0.0446 - val_accuracy: 0.9890\n",
      "Epoch 55/1000\n",
      "55/77 [====================>.........] - ETA: 0s - loss: 0.0205 - accuracy: 0.9943\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 55: val_loss did not improve from 0.04216\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0188 - accuracy: 0.9947 - val_loss: 0.0425 - val_accuracy: 0.9890\n",
      "Epoch 56/1000\n",
      "55/77 [====================>.........] - ETA: 0s - loss: 0.0184 - accuracy: 0.9943\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 56: val_loss improved from 0.04216 to 0.04201, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0190 - accuracy: 0.9945 - val_loss: 0.0420 - val_accuracy: 0.9896\n",
      "Epoch 57/1000\n",
      "52/77 [===================>..........] - ETA: 0s - loss: 0.0187 - accuracy: 0.9949\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 57: val_loss did not improve from 0.04201\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0191 - accuracy: 0.9949 - val_loss: 0.0474 - val_accuracy: 0.9878\n",
      "Epoch 58/1000\n",
      "45/77 [================>.............] - ETA: 0s - loss: 0.0219 - accuracy: 0.9927\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 58: val_loss did not improve from 0.04201\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0198 - accuracy: 0.9943 - val_loss: 0.0436 - val_accuracy: 0.9921\n",
      "Epoch 59/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0179 - accuracy: 0.9953\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 59: val_loss did not improve from 0.04201\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0177 - accuracy: 0.9951 - val_loss: 0.0439 - val_accuracy: 0.9915\n",
      "Epoch 60/1000\n",
      "55/77 [====================>.........] - ETA: 0s - loss: 0.0170 - accuracy: 0.9946\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 60: val_loss did not improve from 0.04201\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0177 - accuracy: 0.9943 - val_loss: 0.0455 - val_accuracy: 0.9884\n",
      "Epoch 61/1000\n",
      "50/77 [==================>...........] - ETA: 0s - loss: 0.0184 - accuracy: 0.9937\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 61: val_loss did not improve from 0.04201\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0176 - accuracy: 0.9943 - val_loss: 0.0444 - val_accuracy: 0.9933\n",
      "Epoch 62/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0159 - accuracy: 0.9947\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 62: val_loss did not improve from 0.04201\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0167 - accuracy: 0.9945 - val_loss: 0.0489 - val_accuracy: 0.9902\n",
      "Epoch 63/1000\n",
      "54/77 [====================>.........] - ETA: 0s - loss: 0.0237 - accuracy: 0.9919\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 63: val_loss did not improve from 0.04201\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0229 - accuracy: 0.9923 - val_loss: 0.0429 - val_accuracy: 0.9896\n",
      "Epoch 64/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0165 - accuracy: 0.9955\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 64: val_loss improved from 0.04201 to 0.04052, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0166 - accuracy: 0.9955 - val_loss: 0.0405 - val_accuracy: 0.9890\n",
      "Epoch 65/1000\n",
      "53/77 [===================>..........] - ETA: 0s - loss: 0.0157 - accuracy: 0.9953\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 65: val_loss improved from 0.04052 to 0.03917, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0145 - accuracy: 0.9959 - val_loss: 0.0392 - val_accuracy: 0.9902\n",
      "Epoch 66/1000\n",
      "46/77 [================>.............] - ETA: 0s - loss: 0.0147 - accuracy: 0.9966\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 66: val_loss did not improve from 0.03917\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0154 - accuracy: 0.9955 - val_loss: 0.0455 - val_accuracy: 0.9908\n",
      "Epoch 67/1000\n",
      "57/77 [=====================>........] - ETA: 0s - loss: 0.0195 - accuracy: 0.9937\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 67: val_loss did not improve from 0.03917\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0192 - accuracy: 0.9937 - val_loss: 0.0399 - val_accuracy: 0.9908\n",
      "Epoch 68/1000\n",
      "57/77 [=====================>........] - ETA: 0s - loss: 0.0143 - accuracy: 0.9956\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 68: val_loss did not improve from 0.03917\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0153 - accuracy: 0.9953 - val_loss: 0.0484 - val_accuracy: 0.9896\n",
      "Epoch 69/1000\n",
      "48/77 [=================>............] - ETA: 0s - loss: 0.0165 - accuracy: 0.9941\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 69: val_loss did not improve from 0.03917\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0163 - accuracy: 0.9941 - val_loss: 0.0471 - val_accuracy: 0.9878\n",
      "Epoch 70/1000\n",
      "55/77 [====================>.........] - ETA: 0s - loss: 0.0168 - accuracy: 0.9946\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 70: val_loss did not improve from 0.03917\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0169 - accuracy: 0.9949 - val_loss: 0.0433 - val_accuracy: 0.9908\n",
      "Epoch 71/1000\n",
      "51/77 [==================>...........] - ETA: 0s - loss: 0.0137 - accuracy: 0.9963\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 71: val_loss did not improve from 0.03917\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0133 - accuracy: 0.9961 - val_loss: 0.0426 - val_accuracy: 0.9927\n",
      "Epoch 72/1000\n",
      "57/77 [=====================>........] - ETA: 0s - loss: 0.0159 - accuracy: 0.9953\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 72: val_loss did not improve from 0.03917\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0135 - accuracy: 0.9961 - val_loss: 0.0410 - val_accuracy: 0.9921\n",
      "Epoch 73/1000\n",
      "49/77 [==================>...........] - ETA: 0s - loss: 0.0115 - accuracy: 0.9962\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 73: val_loss did not improve from 0.03917\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0125 - accuracy: 0.9961 - val_loss: 0.0406 - val_accuracy: 0.9933\n",
      "Epoch 74/1000\n",
      "54/77 [====================>.........] - ETA: 0s - loss: 0.0121 - accuracy: 0.9959\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 74: val_loss did not improve from 0.03917\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0128 - accuracy: 0.9953 - val_loss: 0.0483 - val_accuracy: 0.9902\n",
      "Epoch 75/1000\n",
      "53/77 [===================>..........] - ETA: 0s - loss: 0.0148 - accuracy: 0.9956\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 75: val_loss did not improve from 0.03917\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0141 - accuracy: 0.9951 - val_loss: 0.0403 - val_accuracy: 0.9884\n",
      "Epoch 76/1000\n",
      "57/77 [=====================>........] - ETA: 0s - loss: 0.0135 - accuracy: 0.9959\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 76: val_loss did not improve from 0.03917\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0122 - accuracy: 0.9965 - val_loss: 0.0410 - val_accuracy: 0.9915\n",
      "Epoch 77/1000\n",
      "48/77 [=================>............] - ETA: 0s - loss: 0.0122 - accuracy: 0.9964\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 77: val_loss did not improve from 0.03917\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0135 - accuracy: 0.9957 - val_loss: 0.0545 - val_accuracy: 0.9835\n",
      "Epoch 78/1000\n",
      "54/77 [====================>.........] - ETA: 0s - loss: 0.0123 - accuracy: 0.9945\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 78: val_loss did not improve from 0.03917\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0141 - accuracy: 0.9945 - val_loss: 0.0435 - val_accuracy: 0.9915\n",
      "Epoch 79/1000\n",
      "49/77 [==================>...........] - ETA: 0s - loss: 0.0154 - accuracy: 0.9962\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 79: val_loss did not improve from 0.03917\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0134 - accuracy: 0.9967 - val_loss: 0.0413 - val_accuracy: 0.9921\n",
      "Epoch 80/1000\n",
      "44/77 [================>.............] - ETA: 0s - loss: 0.0146 - accuracy: 0.9947\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 80: val_loss did not improve from 0.03917\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0123 - accuracy: 0.9961 - val_loss: 0.0457 - val_accuracy: 0.9902\n",
      "Epoch 81/1000\n",
      "45/77 [================>.............] - ETA: 0s - loss: 0.0135 - accuracy: 0.9944\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 81: val_loss did not improve from 0.03917\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0131 - accuracy: 0.9953 - val_loss: 0.0423 - val_accuracy: 0.9921\n",
      "Epoch 82/1000\n",
      "46/77 [================>.............] - ETA: 0s - loss: 0.0108 - accuracy: 0.9973\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 82: val_loss did not improve from 0.03917\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0117 - accuracy: 0.9969 - val_loss: 0.0398 - val_accuracy: 0.9908\n",
      "Epoch 83/1000\n",
      "51/77 [==================>...........] - ETA: 0s - loss: 0.0112 - accuracy: 0.9966\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 83: val_loss improved from 0.03917 to 0.03896, saving model to model/keypoint_classifier\\keypoint_classifier_TEST.hdf5\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0132 - accuracy: 0.9959 - val_loss: 0.0390 - val_accuracy: 0.9921\n",
      "Epoch 84/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0105 - accuracy: 0.9972\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 84: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0111 - accuracy: 0.9969 - val_loss: 0.0443 - val_accuracy: 0.9866\n",
      "Epoch 85/1000\n",
      "52/77 [===================>..........] - ETA: 0s - loss: 0.0097 - accuracy: 0.9976\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 85: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0122 - accuracy: 0.9959 - val_loss: 0.0426 - val_accuracy: 0.9921\n",
      "Epoch 86/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0123 - accuracy: 0.9955\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 86: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0107 - accuracy: 0.9963 - val_loss: 0.0413 - val_accuracy: 0.9921\n",
      "Epoch 87/1000\n",
      "50/77 [==================>...........] - ETA: 0s - loss: 0.0115 - accuracy: 0.9966\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 87: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0224 - accuracy: 0.9923 - val_loss: 0.0920 - val_accuracy: 0.9750\n",
      "Epoch 88/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0210 - accuracy: 0.9922\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 88: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0185 - accuracy: 0.9931 - val_loss: 0.0461 - val_accuracy: 0.9915\n",
      "Epoch 89/1000\n",
      "44/77 [================>.............] - ETA: 0s - loss: 0.0112 - accuracy: 0.9957\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 89: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0115 - accuracy: 0.9961 - val_loss: 0.0430 - val_accuracy: 0.9915\n",
      "Epoch 90/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0097 - accuracy: 0.9967\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 90: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0101 - accuracy: 0.9967 - val_loss: 0.0428 - val_accuracy: 0.9927\n",
      "Epoch 91/1000\n",
      "52/77 [===================>..........] - ETA: 0s - loss: 0.0107 - accuracy: 0.9970\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 91: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0118 - accuracy: 0.9965 - val_loss: 0.0443 - val_accuracy: 0.9908\n",
      "Epoch 92/1000\n",
      "57/77 [=====================>........] - ETA: 0s - loss: 0.0153 - accuracy: 0.9951\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 92: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0154 - accuracy: 0.9943 - val_loss: 0.0593 - val_accuracy: 0.9896\n",
      "Epoch 93/1000\n",
      "50/77 [==================>...........] - ETA: 0s - loss: 0.0182 - accuracy: 0.9941\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 93: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0164 - accuracy: 0.9949 - val_loss: 0.0478 - val_accuracy: 0.9896\n",
      "Epoch 94/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0106 - accuracy: 0.9961\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 94: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0109 - accuracy: 0.9959 - val_loss: 0.0448 - val_accuracy: 0.9927\n",
      "Epoch 95/1000\n",
      "49/77 [==================>...........] - ETA: 0s - loss: 0.0123 - accuracy: 0.9955    \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 95: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0107 - accuracy: 0.9965 - val_loss: 0.0441 - val_accuracy: 0.9927\n",
      "Epoch 96/1000\n",
      "55/77 [====================>.........] - ETA: 0s - loss: 0.0103 - accuracy: 0.9966    \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 96: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0094 - accuracy: 0.9974 - val_loss: 0.0447 - val_accuracy: 0.9896\n",
      "Epoch 97/1000\n",
      "51/77 [==================>...........] - ETA: 0s - loss: 0.0090 - accuracy: 0.9975\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 97: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0085 - accuracy: 0.9974 - val_loss: 0.0495 - val_accuracy: 0.9915\n",
      "Epoch 98/1000\n",
      "55/77 [====================>.........] - ETA: 0s - loss: 0.0098 - accuracy: 0.9969\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 98: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0098 - accuracy: 0.9972 - val_loss: 0.0442 - val_accuracy: 0.9933\n",
      "Epoch 99/1000\n",
      "49/77 [==================>...........] - ETA: 0s - loss: 0.0120 - accuracy: 0.9965\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 99: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0102 - accuracy: 0.9972 - val_loss: 0.0520 - val_accuracy: 0.9896\n",
      "Epoch 100/1000\n",
      "53/77 [===================>..........] - ETA: 0s - loss: 0.0086 - accuracy: 0.9973\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 100: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0104 - accuracy: 0.9967 - val_loss: 0.0437 - val_accuracy: 0.9927\n",
      "Epoch 101/1000\n",
      "50/77 [==================>...........] - ETA: 0s - loss: 0.0099 - accuracy: 0.9969\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 101: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0090 - accuracy: 0.9974 - val_loss: 0.0472 - val_accuracy: 0.9902\n",
      "Epoch 102/1000\n",
      "58/77 [=====================>........] - ETA: 0s - loss: 0.0081 - accuracy: 0.9970\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 102: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0090 - accuracy: 0.9974 - val_loss: 0.0444 - val_accuracy: 0.9921\n",
      "Epoch 103/1000\n",
      "48/77 [=================>............] - ETA: 0s - loss: 0.0095 - accuracy: 0.9971\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 103: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0105 - accuracy: 0.9967 - val_loss: 0.0442 - val_accuracy: 0.9896\n",
      "Epoch 104/1000\n",
      "54/77 [====================>.........] - ETA: 0s - loss: 0.0096 - accuracy: 0.9971\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 104: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0091 - accuracy: 0.9972 - val_loss: 0.0409 - val_accuracy: 0.9915\n",
      "Epoch 105/1000\n",
      "48/77 [=================>............] - ETA: 0s - loss: 0.0096 - accuracy: 0.9961\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 105: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0094 - accuracy: 0.9967 - val_loss: 0.0449 - val_accuracy: 0.9915\n",
      "Epoch 106/1000\n",
      "54/77 [====================>.........] - ETA: 0s - loss: 0.0081 - accuracy: 0.9968\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 106: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0108 - accuracy: 0.9957 - val_loss: 0.0882 - val_accuracy: 0.9774\n",
      "Epoch 107/1000\n",
      "42/77 [===============>..............] - ETA: 0s - loss: 0.0155 - accuracy: 0.9944\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 107: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0135 - accuracy: 0.9953 - val_loss: 0.0449 - val_accuracy: 0.9921\n",
      "Epoch 108/1000\n",
      "57/77 [=====================>........] - ETA: 0s - loss: 0.0051 - accuracy: 0.9989\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 108: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0077 - accuracy: 0.9976 - val_loss: 0.0475 - val_accuracy: 0.9915\n",
      "Epoch 109/1000\n",
      "48/77 [=================>............] - ETA: 0s - loss: 0.0089 - accuracy: 0.9977\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 109: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0074 - accuracy: 0.9984 - val_loss: 0.0441 - val_accuracy: 0.9927\n",
      "Epoch 110/1000\n",
      "55/77 [====================>.........] - ETA: 0s - loss: 0.0101 - accuracy: 0.9963\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 110: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0091 - accuracy: 0.9972 - val_loss: 0.0413 - val_accuracy: 0.9927\n",
      "Epoch 111/1000\n",
      "49/77 [==================>...........] - ETA: 0s - loss: 0.0064 - accuracy: 0.9974    \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 111: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0088 - accuracy: 0.9969 - val_loss: 0.0456 - val_accuracy: 0.9927\n",
      "Epoch 112/1000\n",
      "55/77 [====================>.........] - ETA: 0s - loss: 0.0071 - accuracy: 0.9969\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 112: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0079 - accuracy: 0.9965 - val_loss: 0.0439 - val_accuracy: 0.9890\n",
      "Epoch 113/1000\n",
      "52/77 [===================>..........] - ETA: 0s - loss: 0.0062 - accuracy: 0.9982    \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 113: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0068 - accuracy: 0.9980 - val_loss: 0.0467 - val_accuracy: 0.9927\n",
      "Epoch 114/1000\n",
      "57/77 [=====================>........] - ETA: 0s - loss: 0.0058 - accuracy: 0.9986    \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 114: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0079 - accuracy: 0.9980 - val_loss: 0.0480 - val_accuracy: 0.9884\n",
      "Epoch 115/1000\n",
      "49/77 [==================>...........] - ETA: 0s - loss: 0.0065 - accuracy: 0.9987    \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 115: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0066 - accuracy: 0.9978 - val_loss: 0.0457 - val_accuracy: 0.9890\n",
      "Epoch 116/1000\n",
      "57/77 [=====================>........] - ETA: 0s - loss: 0.0123 - accuracy: 0.9956\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 116: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0119 - accuracy: 0.9957 - val_loss: 0.0464 - val_accuracy: 0.9902\n",
      "Epoch 117/1000\n",
      "51/77 [==================>...........] - ETA: 0s - loss: 0.0099 - accuracy: 0.9957\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 117: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0103 - accuracy: 0.9957 - val_loss: 0.0491 - val_accuracy: 0.9890\n",
      "Epoch 118/1000\n",
      "52/77 [===================>..........] - ETA: 0s - loss: 0.0082 - accuracy: 0.9967\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 118: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0085 - accuracy: 0.9967 - val_loss: 0.0559 - val_accuracy: 0.9872\n",
      "Epoch 119/1000\n",
      "50/77 [==================>...........] - ETA: 0s - loss: 0.0078 - accuracy: 0.9981    \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 119: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0082 - accuracy: 0.9978 - val_loss: 0.0450 - val_accuracy: 0.9902\n",
      "Epoch 120/1000\n",
      "57/77 [=====================>........] - ETA: 0s - loss: 0.0109 - accuracy: 0.9962\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 120: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0101 - accuracy: 0.9965 - val_loss: 0.0424 - val_accuracy: 0.9915\n",
      "Epoch 121/1000\n",
      "47/77 [=================>............] - ETA: 0s - loss: 0.0074 - accuracy: 0.9973\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 121: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0068 - accuracy: 0.9976 - val_loss: 0.0465 - val_accuracy: 0.9908\n",
      "Epoch 122/1000\n",
      "58/77 [=====================>........] - ETA: 0s - loss: 0.0078 - accuracy: 0.9978    \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 122: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0070 - accuracy: 0.9980 - val_loss: 0.0450 - val_accuracy: 0.9902\n",
      "Epoch 123/1000\n",
      "51/77 [==================>...........] - ETA: 0s - loss: 0.0056 - accuracy: 0.9975    \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 123: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0067 - accuracy: 0.9976 - val_loss: 0.0450 - val_accuracy: 0.9915\n",
      "Epoch 124/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0066 - accuracy: 0.9983\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 124: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0062 - accuracy: 0.9982 - val_loss: 0.0437 - val_accuracy: 0.9927\n",
      "Epoch 125/1000\n",
      "48/77 [=================>............] - ETA: 0s - loss: 0.0061 - accuracy: 0.9984    \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 125: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0058 - accuracy: 0.9986 - val_loss: 0.0433 - val_accuracy: 0.9927\n",
      "Epoch 126/1000\n",
      "52/77 [===================>..........] - ETA: 0s - loss: 0.0067 - accuracy: 0.9970\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 126: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0073 - accuracy: 0.9972 - val_loss: 0.0483 - val_accuracy: 0.9884\n",
      "Epoch 127/1000\n",
      "49/77 [==================>...........] - ETA: 0s - loss: 0.0081 - accuracy: 0.9971\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 127: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0074 - accuracy: 0.9974 - val_loss: 0.0508 - val_accuracy: 0.9915\n",
      "Epoch 128/1000\n",
      "56/77 [====================>.........] - ETA: 0s - loss: 0.0113 - accuracy: 0.9964\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 128: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0124 - accuracy: 0.9963 - val_loss: 0.0480 - val_accuracy: 0.9915\n",
      "Epoch 129/1000\n",
      "49/77 [==================>...........] - ETA: 0s - loss: 0.0081 - accuracy: 0.9971    \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 129: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0073 - accuracy: 0.9976 - val_loss: 0.0464 - val_accuracy: 0.9933\n",
      "Epoch 130/1000\n",
      "53/77 [===================>..........] - ETA: 0s - loss: 0.0081 - accuracy: 0.9968\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 130: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0088 - accuracy: 0.9963 - val_loss: 0.0533 - val_accuracy: 0.9921\n",
      "Epoch 131/1000\n",
      "46/77 [================>.............] - ETA: 0s - loss: 0.0036 - accuracy: 0.9997    \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 131: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 2ms/step - loss: 0.0076 - accuracy: 0.9980 - val_loss: 0.0402 - val_accuracy: 0.9908\n",
      "Epoch 132/1000\n",
      "55/77 [====================>.........] - ETA: 0s - loss: 0.0059 - accuracy: 0.9983\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 132: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0070 - accuracy: 0.9980 - val_loss: 0.0489 - val_accuracy: 0.9927\n",
      "Epoch 133/1000\n",
      "52/77 [===================>..........] - ETA: 0s - loss: 0.0049 - accuracy: 0.9988\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n",
      "Epoch 133: val_loss did not improve from 0.03896\n",
      "77/77 [==============================] - 0s 1ms/step - loss: 0.0058 - accuracy: 0.9988 - val_loss: 0.0456 - val_accuracy: 0.9896\n",
      "Epoch 133: early stopping\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<keras.callbacks.History at 0x1ad4213f130>"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.fit(\n",
    "    X_train,\n",
    "    y_train,\n",
    "    epochs=1000,\n",
    "    batch_size=64,\n",
    "    validation_data=(X_test, y_test),\n",
    "    callbacks=[cp_callback, es_callback]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "id": "RBkmDeUW9hE4"
   },
   "outputs": [],
   "source": [
    "# Loading the saved model\n",
    "# model = tf.keras.models.load_model(model_save_path)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "pxvb2Y299hE3",
    "outputId": "7015e279-0501-4f24-d1b5-90652d2de17d"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "26/26 [==============================] - 0s 1ms/step - loss: 0.0456 - accuracy: 0.9896\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n"
     ]
    }
   ],
   "source": [
    "# Model evaluation\n",
    "# TODO Test on loaded model\n",
    "val_loss, val_acc = model.evaluate(X_test, y_test, batch_size=64)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "tFz9Tb0I9hE4",
    "outputId": "bb8a62a9-bf7d-4d99-8099-bda4e2e1c73a"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[9.9912149e-01 8.7853073e-04 5.3556243e-14 4.2972977e-13 2.8450411e-13\n",
      " 7.1456529e-25 8.2106750e-18 1.3376958e-24 2.8211950e-24 8.3693149e-21]\n",
      "0\n"
     ]
    }
   ],
   "source": [
    "# Inference test\n",
    "predict_result = model.predict(np.array([X_test[0]]))\n",
    "print(np.squeeze(predict_result))\n",
    "print(np.argmax(np.squeeze(predict_result)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "S3U4yNWx9hE4"
   },
   "source": [
    "# Confusion matrix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 646
    },
    "id": "AP1V6SCk9hE5",
    "outputId": "efce96b9-ca1c-44a5-ef77-58f1d5fc154c"
   },
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 504x432 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Classification Report\n",
      "              precision    recall  f1-score   support\n",
      "\n",
      "           0       1.00      1.00      1.00       429\n",
      "           1       1.00      1.00      1.00       416\n",
      "           2       0.99      0.97      0.98       364\n",
      "           3       1.00      0.99      1.00       157\n",
      "           4       0.95      1.00      0.98        42\n",
      "           5       1.00      1.00      1.00        46\n",
      "           6       0.96      1.00      0.98        26\n",
      "           7       1.00      1.00      1.00        49\n",
      "           8       0.88      0.93      0.90        60\n",
      "           9       0.98      1.00      0.99        49\n",
      "\n",
      "    accuracy                           0.99      1638\n",
      "   macro avg       0.98      0.99      0.98      1638\n",
      "weighted avg       0.99      0.99      0.99      1638\n",
      "\n"
     ]
    }
   ],
   "source": [
    "import pandas as pd\n",
    "import seaborn as sns\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.metrics import confusion_matrix, classification_report\n",
    "\n",
    "def print_confusion_matrix(y_true, y_pred, report=True):\n",
    "    labels = sorted(list(set(y_true)))\n",
    "    cmx_data = confusion_matrix(y_true, y_pred, labels=labels)\n",
    "    \n",
    "    df_cmx = pd.DataFrame(cmx_data, index=labels, columns=labels)\n",
    " \n",
    "    fig, ax = plt.subplots(figsize=(7, 6))\n",
    "    sns.heatmap(df_cmx, annot=True, fmt='g' ,square=False)\n",
    "    ax.set_ylim(len(set(y_true)), 0)\n",
    "    plt.show()\n",
    "    \n",
    "    if report:\n",
    "        print('Classification Report')\n",
    "        print(classification_report(y_test, y_pred))\n",
    "\n",
    "Y_pred = model.predict(X_test)\n",
    "y_pred = np.argmax(Y_pred, axis=1)\n",
    "\n",
    "print_confusion_matrix(y_test, y_pred)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "FNP6aqzc9hE5"
   },
   "source": [
    "# Convert to model for Tensorflow-Lite"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "id": "ODjnYyld9hE6"
   },
   "outputs": [],
   "source": [
    "# Save as a model dedicated to inference\n",
    "model.save(model_save_path, include_optimizer=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "zRfuK8Y59hE6",
    "outputId": "106250fb-84e1-4ee8-bc8e-dcedb2bfd31c"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "INFO:tensorflow:Assets written to: C:\\Users\\PpwqDhr\\AppData\\Local\\Temp\\tmpn4i53ois\\assets\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING:absl:Buffer deduplication procedure will be skipped when flatbuffer library is not properly loaded\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "7840"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Transform model (quantization)\n",
    "\n",
    "converter = tf.lite.TFLiteConverter.from_keras_model(model)\n",
    "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n",
    "tflite_quantized_model = converter.convert()\n",
    "\n",
    "open(tflite_save_path, 'wb').write(tflite_quantized_model)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "CHBPBXdx9hE6"
   },
   "source": [
    "## Inference test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "mGAzLocO9hE7"
   },
   "outputs": [],
   "source": [
    "interpreter = tf.lite.Interpreter(model_path=tflite_save_path)\n",
    "interpreter.allocate_tensors()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "oQuDK8YS9hE7"
   },
   "outputs": [],
   "source": [
    "# Get I / O tensor\n",
    "input_details = interpreter.get_input_details()\n",
    "output_details = interpreter.get_output_details()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "2_ixAf_l9hE7"
   },
   "outputs": [],
   "source": [
    "interpreter.set_tensor(input_details[0]['index'], np.array([X_test[0]]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "s4FoAnuc9hE7",
    "outputId": "330d050b-a3fb-41ce-fa07-dc7a48d715e7",
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 117 µs, sys: 7 µs, total: 124 µs\n",
      "Wall time: 132 µs\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "# Inference implementation\n",
    "interpreter.invoke()\n",
    "tflite_results = interpreter.get_tensor(output_details[0]['index'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "vONjp19J9hE8",
    "outputId": "9338c9f1-499b-4e10-844d-950075e98a75"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1.0000000e+00 1.7798680e-13 5.1755124e-26 1.1783223e-18 1.0188586e-18\n",
      " 1.1212574e-26 2.5901723e-24 2.6419864e-15]\n",
      "0\n"
     ]
    }
   ],
   "source": [
    "print(np.squeeze(tflite_results))\n",
    "print(np.argmax(np.squeeze(tflite_results)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "2GCHB0ELGs60"
   },
   "source": [
    "## Download model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "a2jM8I3jGdF6",
    "outputId": "bd2c08cc-d57c-4589-e4fa-f80389176b96"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "updating: keypoint_classifier/ (stored 0%)\n",
      "updating: keypoint_classifier/keypoint_classifier.tflite (deflated 22%)\n",
      "updating: keypoint_classifier/keypoint_classifier.hdf5 (deflated 60%)\n"
     ]
    }
   ],
   "source": [
    "!zip -r model.zip keypoint_classifier  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "vEqyprC6cMVF"
   },
   "source": [
    "\n",
    "\n",
    "---\n",
    "\n",
    "\n",
    "# ❗️Hyperparameters Tuning"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "KrjjSqlLcQ4O"
   },
   "outputs": [],
   "source": [
    "%load_ext tensorboard\n",
    "from tensorboard.plugins.hparams import api as hp"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "YO6VffaRcY3R"
   },
   "outputs": [],
   "source": [
    "# Init parameters to tune\n",
    "HP_NUM_UNITS_1 = hp.HParam('num_units_1', hp.Discrete([16, 32, 64]))\n",
    "HP_NUM_UNITS_2 = hp.HParam('num_units_2', hp.Discrete([8, 16, 32]))\n",
    "HP_NUM_UNITS_3 = hp.HParam('num_units_3', hp.Discrete([8, 16, 32]))\n",
    "HP_DROPOUT = hp.HParam('dropout', hp.RealInterval(0.0, 0.2))\n",
    "HP_OPTIMIZER = hp.HParam('optimizer', hp.Discrete(['adam', 'sgd']))\n",
    "\n",
    "METRIC_ACCURACY = 'accuracy'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "eMysvzFxctmG"
   },
   "outputs": [],
   "source": [
    "with tf.summary.create_file_writer('logs/hparam_tuning').as_default():\n",
    "  hp.hparams_config(\n",
    "    hparams=[HP_NUM_UNITS_1,HP_NUM_UNITS_2,HP_NUM_UNITS_3, HP_DROPOUT, HP_OPTIMIZER],\n",
    "    metrics=[hp.Metric(METRIC_ACCURACY, display_name='Accuracy')],\n",
    "  )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "XSDYqpKZgOBw"
   },
   "outputs": [],
   "source": [
    "# Model checkpoint callback\n",
    "cp_callback = tf.keras.callbacks.ModelCheckpoint(\n",
    "    model_save_path, verbose=1, save_weights_only=False, save_best_only=True)\n",
    "# Callback for early stopping\n",
    "es_callback = tf.keras.callbacks.EarlyStopping(patience=15, verbose=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "8ssEmXpJcxSp"
   },
   "outputs": [],
   "source": [
    "def train_test_model(hparams):\n",
    "\n",
    "  model = tf.keras.models.Sequential([\n",
    "    tf.keras.layers.Input((21 * 2, )),\n",
    "    tf.keras.layers.Dropout(hparams[HP_DROPOUT]),\n",
    "    tf.keras.layers.Dense(hparams[HP_NUM_UNITS_1], activation='relu'),\n",
    "    tf.keras.layers.Dropout(hparams[HP_DROPOUT]),\n",
    "    tf.keras.layers.Dense(hparams[HP_NUM_UNITS_2], activation='relu'),\n",
    "    tf.keras.layers.Dropout(hparams[HP_DROPOUT]),\n",
    "    tf.keras.layers.Dense(hparams[HP_NUM_UNITS_3], activation='relu'),\n",
    "    tf.keras.layers.Dense(NUM_CLASSES, activation='softmax')\n",
    "])\n",
    "  \n",
    "  model.compile(\n",
    "    optimizer=hparams[HP_OPTIMIZER],\n",
    "    loss='sparse_categorical_crossentropy',\n",
    "    metrics=['accuracy']\n",
    ")\n",
    "  \n",
    "  cp_callback = tf.keras.callbacks.ModelCheckpoint(\n",
    "    model_save_path, verbose=1, save_weights_only=False, save_best_only=True)\n",
    "\n",
    "  model.fit(\n",
    "    X_train,\n",
    "    y_train,\n",
    "    epochs=50,\n",
    "    batch_size=64,\n",
    "    validation_data=(X_test, y_test),\n",
    "    callbacks=[\n",
    "               cp_callback,\n",
    "               es_callback,\n",
    "               ]\n",
    "  ) \n",
    "\n",
    "  # Load model with best accuracy\n",
    "  model = tf.keras.models.load_model(model_save_path)\n",
    "\n",
    "  _, accuracy = model.evaluate(X_test, y_test)\n",
    "  return accuracy\n",
    "\n",
    "def run(run_dir, hparams):\n",
    "  with tf.summary.create_file_writer(run_dir).as_default():\n",
    "    hp.hparams(hparams)  # record the values used in this trial\n",
    "    accuracy = train_test_model(hparams)\n",
    "    tf.summary.scalar(METRIC_ACCURACY, accuracy, step=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "5pO9W84DdHVL"
   },
   "outputs": [],
   "source": [
    "session_num = 0\n",
    "\n",
    "for num_units_1 in HP_NUM_UNITS_1.domain.values:\n",
    "  for num_units_2 in HP_NUM_UNITS_2.domain.values:\n",
    "    for num_units_3 in HP_NUM_UNITS_3.domain.values:\n",
    "      for dropout_rate in np.arange(HP_DROPOUT.domain.min_value, HP_DROPOUT.domain.max_value, 0.1):\n",
    "        for optimizer in HP_OPTIMIZER.domain.values:\n",
    "          hparams = {\n",
    "              HP_NUM_UNITS_1: num_units_1,\n",
    "              HP_NUM_UNITS_2: num_units_2,\n",
    "              HP_NUM_UNITS_3: num_units_3,\n",
    "              HP_DROPOUT: dropout_rate,\n",
    "              HP_OPTIMIZER: optimizer,\n",
    "          }\n",
    "          run_name = \"run-%d\" % session_num\n",
    "          print('--- Starting trial: %s' % run_name)\n",
    "          print({h.name: hparams[h] for h in hparams})\n",
    "          run('logs/hparam_tuning/' + run_name, hparams)\n",
    "          session_num += 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "21knbMYldaUn"
   },
   "outputs": [],
   "source": [
    "# !ATTENTION! Works only in Colab\n",
    "%tensorboard --logdir logs/hparam_tuning"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "J6_UH6jttBsD"
   },
   "outputs": [],
   "source": [
    "!rm -rf logs"
   ]
  }
 ],
 "metadata": {
  "accelerator": "GPU",
  "colab": {
   "collapsed_sections": [],
   "name": "Keypoint_model_training.ipynb",
   "provenance": [],
   "toc_visible": true
  },
  "kernelspec": {
   "display_name": "PyCharm (tello-gesture-control-main)",
   "language": "python",
   "name": "pycharm-6a5e4b1a"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
